<?php
// +----------------------------------------------------------------------
// | INPHP
// +----------------------------------------------------------------------
// | Copyright (c) 2021 https://inphp.cc All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://opensource.org/licenses/MIT )
// +----------------------------------------------------------------------
// | Author: lulanyin <me@lanyin.lu>
// +----------------------------------------------------------------------
namespace Inphp\Service;

use Inphp\Cache;
use Inphp\Service\Http\Response;
use Inphp\Service\Object\Client;
use Inphp\Service\Object\Message;
use Inphp\Service\Object\Module;
use Inphp\Service\Object\RouterStatus;
use Swoole\Coroutine;

class Context
{
    /**
     * 临时上下文数据
     * 仅 PHP-FPM 使用
     * @var array
     */
    public static array $contexts = [];

    /**
     * 获取临时上下文对象
     * @param string $name
     * @param int $client_id
     * @param bool $global
     * @return mixed
     */
    public static function get(string $name, int $client_id = 0, bool $global = false) : mixed
    {
        if(Service::isSwoole() && !$global){
            if($client_id > 0){
                //从缓存中读取
                $cache_key = "client_{$client_id}";
                $data = Cache::get($cache_key);
                $data = is_array($data) ? $data : [];
                if(!empty($data)){
                    return $data[$name] ?? null;
                }
                return null;
            }else{
                //从协程中读取
                $contexts = Coroutine::getContext();
                return $contexts[$name] ?? null;
            }
        }else{
            return self::$contexts[$name] ?? null;
        }
    }

    /**
     * 保存临时上下文对象
     * @param string $name
     * @param mixed $value
     * @param int $client_id
     * @param bool $global
     */
    public static function set(string $name, mixed $value, int $client_id = 0, bool $global = false) : void
    {
        if(Service::isSwoole() && !$global){
            if($client_id > 0){
                //使用缓存保存
                $cache_key = "client_{$client_id}";
                $data = Cache::get($cache_key);
                $data = is_array($data) ? $data : [];
                $data[$name] = $value;
                Cache::set($cache_key, $data);
            }else{
                //保存到协程中
                Coroutine::getContext()[$name] = $value;
            }
        }else{
            self::$contexts[$name] = $value;
        }
    }

    /**
     * 清除临时上下文对象
     * @param int $client_id
     */
    public static function clean(int $client_id = 0) : void
    {
        if(Service::isSwoole() && $client_id > 0){
            $cache_key = "client_{$client_id}";
            Cache::remove($cache_key);
        }else{
            self::$contexts = [];
        }
    }

    /**
     * 保存客户端ID
     * @param int $client_id
     */
    public static function setClientId(int $client_id) : void
    {
        if($client_id > 0){
            if(Service::isSwoole()){
                Coroutine::getContext()['client_id'] = $client_id;
            }else{
                self::$contexts['client_id'] = $client_id;
            }
        }
    }

    /**
     * 获取当前客户ID
     * @return int
     */
    public static function getClientId() : int
    {
        if(Service::isSwoole()){
            $client_id = Coroutine::getContext()['client_id'] ?? 0;
            $client_id = is_numeric($client_id) && $client_id > 0 ? $client_id : 0;
        }else{
            $client_id = self::$contexts['client_id'] ?? 0;
        }
        return $client_id;
    }

    /**
     * 保存客户端
     * @param Client $client
     * @param int $client_id
     */
    public static function setClient(Client $client, int $client_id = 0) : void
    {
        self::set('client', $client, $client_id);
    }

    /**
     * 获取客户端对象
     * @param int $client_id
     * @return Client|null
     */
    public static function getClient(int $client_id = 0) : Client|null
    {
        $client = self::get('client', $client_id);
        if(is_array($client)){
            return new Client($client);
        }
        return $client;
    }

    /**
     * 移除客户端对象
     * @param int $client_id
     */
    public static function removeClient(int $client_id = 0) : void
    {
        self::set('client', null, $client_id);
    }

    /**
     * 保存 Frame 对象
     * @param \Swoole\WebSocket\Frame $frame
     */
    public static function setWebsocketFrame(\Swoole\WebSocket\Frame $frame) : void
    {
        self::set('websocket_frame', $frame);
    }

    /**
     * 获取Frame对象
     * @return \Swoole\WebSocket\Frame|null
     */
    public static function getWebsocketFrame() : \Swoole\WebSocket\Frame|null
    {
        return self::get('websocket_frame');
    }

    /**
     * 保存临时Message对象，该对象保存的是客户端上传的消息
     * @param Message $message
     */
    public static function setMessage(Message $message) : void
    {
        self::set('message', $message);
    }

    /**
     * 获取临时Message对象，该对象保存的是客户端上传的消息
     * @return Message|null
     */
    public static function getMessage() : Message|null
    {
        return self::get('message');
    }

    /**
     * 保存临时路由状态
     * @param RouterStatus $routerStatus
     */
    public static function setRouterStatus(RouterStatus $routerStatus) : void
    {
        self::set('router_status', $routerStatus);
    }

    /**
     * 获取临时路由状态
     * @return RouterStatus|null
     */
    public static function getRouterStatus() : RouterStatus|null
    {
        return self::get('router_status');
    }

    /**
     * 保存临时 Response 对象，HTTP 服务使用
     * @param Response $response
     */
    public static function setResponse(Response $response) : void
    {
        self::set('response', $response);
    }

    /**
     * 获取临时 Response 对象
     * @return Response|null
     */
    public static function getResponse() : Response|null
    {
        return self::get('response');
    }

    /**
     * 保存临时模块
     * @param Module $module
     */
    public static function setModule(Module $module) : void
    {
        self::set('module', $module);
    }

    /**
     * 获取临时模块
     * @return Module|null
     */
    public static function getModule() : Module | null
    {
        return self::get('module');
    }


}